home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-08-25 | 33.7 KB | 1,197 lines |
- Page 60,132
- ;---------------------------------------------------------------
- ; BEGIN LISTING 2
- ;---------------------------------------------------------------
- ;
- ; 386LOAD.ASM Copyright (c) 1991 Robert Collins
- ;
- ; This program demonstrates various aspects of CPU
- ; behavior that become apparent when using LOADALL.
- ;
- ; Test 1: Checks that LOADALL loads all the general-
- ; purpose registers; loads the segment registers
- ; with values that are inconsistant to their
- ; respective descriptor cache registers.
- ;
- ; Test 2: Access extended memory in real mode.
- ;
- ; Test 3: Tests that the Present bit in a descriptor
- ; table can be loaded using LOADALL without
- ; generating exception 11. But when the segment
- ; is accessed, exception 13 is generated.
- ; NOTE: This test should be done in protected
- ; mode, but can be done in real mode. 1) In real
- ; mode, no error code is pushed on the stack
- ; (possibly due to a bug in the CPU). 2) Also,
- ; when this test is executed in real-mode, the
- ; '386 fails to set the Present bit when the
- ; segment is subsequently loaded. This latter
- ; condition is clearly a bug in the '386.
- ;
- ; Test 4: Test 32-bit protected mode.
- ;
- ; Test 5: Test 32-bit real mode -- a mode that is an
- ; illegal mode for the CPU.
- ;
- ; Test 6: Test that the Granularity bit in the descriptor
- ; cache register has no affect on the segment
- ; limit field.
- ;
- ; Test 7: Test execution breakpoints.
- ;
- ; Test 8: Test data breakpoints.
- ;
- ; This program was written for Microsoft MASM 5.1.
- ; This program contains compiler directives and branching
- ; techniques that might not be available on previous
- ; versions of the Macro Assembler, nor in competitive
- ; products.
- ;
- ;---------------------------------------------------------------
-
- ;---------------------------------------------------------------
- ; Compiler directives
- ;---------------------------------------------------------------
- Title LOADALL_386
- .radix 16
- .8086
-
-
- ;---------------------------------------------------------------
- ; Interrupt vector segment
- ;---------------------------------------------------------------
- ABS0 segment at 0
- org 6*4
- INT_6 dd ?
- ABS0 ends
-
-
- ;---------------------------------------------------------------
- ; Structure definitions
- ;---------------------------------------------------------------
- Desc_cache STRUC
- db 0
- _Type db ?
- _CS32 db 0
- db 0
- _Addr dd ?
- _Limit dd ?
- Desc_cache ENDS
-
-
- Loadall_struc STRUC
- _Cr0 dd 0
- _Eflags dd 2
- _Eip dd 0
- _Edi dd 66666666h
- _Esi dd 77777777h
- _Ebp dd 55555555h
- _Esp dd 88888888h
- _Ebx dd 22222222h
- _Edx dd 44444444h
- _Ecx dd 33333333h
- _Eax dd 11111111h
- _Dr6 dd 0
- _Dr7 dd 0
- _Tr dd 0
- _Ldt dd 0
- _Gs dd 5555h
- _Fs dd 4444h
- _Ds dd 2222h
- _Ss dd 6666h
- _Cs dd 1111h
- _Es dd 3333h
- TSS_Desc dd 00008900h,00070000h,00000800h
- IDT_Desc dd 00000000h,00000000h,000003ffh
- Gdt_Desc dd 00000000h,00000000h,00000000h
- Ldt_Desc dd 00008200h,00090000h,00000088h
- GS_Desc dd 00009300h,00050000h,0000ffffh
- FS_Desc dd 00009300h,00040000h,0000ffffh
- DS_Desc dd 00009300h,00020000h,0000ffffh
- SS_Desc dd 00009300h,00060000h,0000ffffh
- CS_Desc dd 00009b00h,00000000h,0000ffffh
- ES_Desc dd 00009300h,00030000h,00fffffch
- Loadall_Struc ENDS
-
-
- Descriptor STRUC
- Seg_limit dw ? ; Segment limit
- Base_A15_A00 dw ? ; A00..A15 of base address
- Base_A23_A16 db ? ; A16..A23 of base address
- Access_rights db ? ; Segment access rights
- Limit_A19_A16 db ? ; Granularity, Op-size,
- ; Limit A16..A19
- Base_A31_A24 db ? ; A24..A31 of base address
- Descriptor ENDS
-
-
- INT_Desc STRUC
- IGate_Offset dw ? ; Offset of handler
- CSEG_Sel dw ? ; Code segment selector
- db 0
- db 86h ; 286 interrupt gate=16bit
- ; CS:IP, FLAGS
- Resvd dw 0 ; Reserved=0
- INT_Desc ENDS
-
-
- ;-----------------------------------------------------------------------------
- ; Macro definitions
- ;-----------------------------------------------------------------------------
- Init_descriptor macro segment,offset,desc_name
- push ax
- push dx
- push si
- push es
- mov ax,&segment ;; get segment name
- mov es,ax ;; to form 24 bit address
- mov si,&offset ;;
- mov ax,es ; point to control block
- xor dh,dh ; clear upper register
- mov dl,ah ; build high byte of 32-bit address
- shr dl,4 ; use only high nibble from (AX)
- shl ax,4 ; strip high nibble from segment
- add ax,si ; add the GDT offset to develop low word
- adc dx,0 ; adjust high byte if carry from low
- mov &desc_name.Base_A15_A00,ax ;; low word of address
- mov &desc_name.Base_A23_A16,dl ;; high byte of address
- mov &desc_name.Base_A31_A24,dh ;; high byte of linear address
- pop es
- pop si
- pop dx
- pop ax
- endm
-
-
- FARJMP MACRO destination,selector ; dynamic JMP FAR SEG:OFF
- db 0eah ;; jmp instruction
- dw offset destination ;; offset word
- dw selector ;; segment selector word
- endm
-
-
- LONGJMP MACRO destination,selector ; dynamic JMP FAR SEG:OFF
- db 0eah ;; jmp instruction
- dd offset destination ;; offset word
- dw selector ;; segment selector word
- endm
-
-
- IO_DELAY MACRO
- out 0edh,ax
- endm
-
- LOADALL MACRO
- db 0fh,07h
- ENDM
-
-
- PRINT_STRING MACRO MSG_NAME
- mov ah,9
- mov dx,offset MSG_NAME
- int 21h
- ENDM
-
-
- _DATA SEGMENT PARA PUBLIC 'DATA'
- ;---------------------------------------------------------------
- ; Equates & local variables
- ;---------------------------------------------------------------
- ; Protected mode access rights
- ;---------------------------------------------------------------
- CS_access equ 10011011b
- DS_access equ 10010011b
-
- ;---------------------------------------------------------------
- ; Text equates
- ;---------------------------------------------------------------
- CRLF equ <0dh,0ah>
- CRLF$ equ <CRLF,'$'>
- INT6 equ [bp-4]
-
- ;---------------------------------------------------------------
- ; Loadall table(s)
- ;---------------------------------------------------------------
- Loadall_tbl Loadall_struc <>
- Machine_State Loadall_struc <>
-
- ;---------------------------------------------------------------
- ; Global Descriptor Table
- ;---------------------------------------------------------------
- GDT_386 Descriptor <Gdt3_len-1,,,DS_access>
- CSEG3 Descriptor <0ffffh,0,0,CS_access>
- DSEG3 Descriptor <0ffffh,0,20h,DS_access>
- Gdt3_len equ $-Gdt_386
-
- ;---------------------------------------------------------------
- ; Interrupt Descriptor Table
- ;---------------------------------------------------------------
- IDT_386 INT_Desc <Offset INT13,CSEG3-GDT_386> ; INT00
- INT_Desc <Offset INT01,CSEG3-GDT_386> ; INT01
- INT_Desc <Offset INT13,CSEG3-GDT_386> ; INT02
- INT_Desc <Offset INT13,CSEG3-GDT_386> ; INT03
- INT_Desc <Offset INT13,CSEG3-GDT_386> ; INT04
- INT_Desc <Offset INT13,CSEG3-GDT_386> ; INT05
- INT_Desc <Offset INT13,CSEG3-GDT_386> ; INT06
- INT_Desc <Offset INT13,CSEG3-GDT_386> ; INT07
- INT_Desc <Offset INT13,CSEG3-GDT_386> ; INT08
- INT_Desc <Offset INT13,CSEG3-GDT_386> ; INT09
- INT_Desc <Offset INT13,CSEG3-GDT_386> ; INT0a
- INT_Desc <Offset INT13,CSEG3-GDT_386> ; INT0b
- INT_Desc <Offset INT13,CSEG3-GDT_386> ; INT0c
- INT_Desc <Offset INT13,CSEG3-GDT_386> ; INT0d
- IDT3_Len equ $-IDT_386
-
- ;---------------------------------------------------------------
- ; Misc. local variables
- ;---------------------------------------------------------------
- Mem_buffer db 400h dup (0) ; Store 2M mem.
- Buffer db 40h dup (0)
- Buffer2 dw 10h dup (0)
-
- RM_IDT3_Ptr dw (256d*4)-1 ; Real-mode IDT
- dd 0 ; pointer
- dw 0
-
-
- ;---------------------------------------------------------------
- ; String Messages
- ;---------------------------------------------------------------
- Passed db " PASSED.",CRLF$
- Failed db "--> FAILED <--",CRLF$
- Not_386 db "Not 80386 class computer.",CRLF$
- Rmvd db "LOADALL removed from 80386 mask.",CRLF$
- RFail db "Registers weren't loaded correctly."
- LF db CRLF$
-
- ;---------------------------------------------------------------
- ; I'm doing this wierd string definition technique to limit the
- ; page width to 64 characters.
- ;---------------------------------------------------------------
- Test_1 label word
- db "Test 1: Testing 386 LOADALL instruction: ",24
-
- Test_2 label word
- db "Test 2: Testing extended memory in real mode: ",24
-
- Test_3 label word
- db "Test 3: Testing Present BIT in descriptor: ",24
-
- Test_4 label word
- db "Test 4: Testing 32-bit protected mode: ",24
-
- Test_5 label word
- db "Test 5: Testing 32-bit real mode: ",24
-
- Test_6 label word
- db "Test 6: Testing Granularity BIT: ",24
-
- Test_7 label word
- db "Test 7: Testing Execution breakpoints: ",24
-
- Test_8 label word
- db "Test 8: Testing byte, write, data breakpoints: ",24
-
- _DATA ENDS
-
-
- _TEXT SEGMENT PARA PUBLIC 'CODE'
- ASSUME CS:_TEXT, ds:_DATA, ES:_DATA, SS:STACK
- .386P
- ;---------------------------------------------------------------
- ; A little CS-relative data for the stack pointer. This is
- ; to avoid using other kludge techniques, caused by using
- ; LOADALL, that make using the data segment undesirable.
- ;---------------------------------------------------------------
- Stack_ptr dd 0
- dw 0
-
- ;---------------------------------------------------------------
- LOADALL_386 proc far
- ;---------------------------------------------------------------
- PUSH DS ; Setup the stack to
- XOR AX,AX ; return to DOS
- PUSH AX
-
- MOV AX,_Data
- MOV DS,AX
- MOV ES,AX
-
- ;---------------------------------------------------------------
- ; Check CPU type
- ;---------------------------------------------------------------
- Call CPU_Type ; 386, 486?
- cmp ax,3 ; 386?
- je short @F ; yep
- Print_String LF
- Print_String Not_386
- retf ; go split
-
- @@: enter 4,0 ; create stack frame
- mov word ptr INT6,offset INT6_handler
- mov INT6+2,cs
- call set_INT6_vector ; set our INT6 handler
- cli
- Call Save_State
- Print_String LF
- Print_String Test_1
- Init_descriptor <seg Gdt_386>,<offset Gdt_386>,Gdt_386
- Init_descriptor cs, 0,CSEG3
-
- ;---------------------------------------------------------------
- ;
- ; TEST1: 16-bit Real mode
- ; Test general purpose registers
- ; Test Segment registers
- ; Test Descriptor cache base address
- ;
- ; (1) Setup LOADALL structures, and pointers
- ; (2) Execute LOADALL
- ; (3) Verify results of the test
- ;
- ;---------------------------------------------------------------
- mov eax,cs ; Prepare a 32-bit
- shl eax,4 ; physical address that
- ; is put in the LOADALL
- ; CS descriptor cache.
- mov Loadall_tbl.CS_Desc._Addr,eax
-
- mov eax,cr0 ; Initialize CR0 in the
- and eax,0fffffff0h ; LOADALL data table
- mov Loadall_tbl._CR0,eax ; DR6, DR7, EIP
- mov eax,dr6
- mov ebx,dr7
- mov Loadall_tbl._DR6,eax
- mov Loadall_tbl._DR7,ebx
- mov Loadall_tbl._EIP,offset Verify_State
- mov dword ptr cs:stack_ptr,esp ; save SS:ESP
- mov word ptr cs:stack_ptr[4],ss
- mov edi,offset loadall_tbl
- LOADALL
- nop ; If LOADALL is removed
- Print_String failed ; from the CPU mask,
- Print_String Rmvd ; then fall through
- ; to here.
- Loadall_RET:
- call Restore_state
- call set_int6_vector
- leave
- retf
-
- ;---------------------------------------------------------------
- Verify_State: ; Verify that LOADALL worked
- ;---------------------------------------------------------------
- ; This is where we land for the first test of '386 LOADALL.
- ; The purpose of this test is to verify that all the general
- ; purpose registers get loaded correctly. Specifically, we are
- ; testing to verify that all segment registers contain values
- ; that don't correspond to the memory addresses they appear to
- ; be pointing to. In other words, we are checking that the
- ; that the segment registers have one value, while their
- ; associated hidden descriptor cache registers have different
- ; values.
- ;---------------------------------------------------------------
- cmp eax,11111111h ; Test EAX
- jne @F
- cmp ebx,22222222h ; Test EBX
- jne @F
- cmp ecx,33333333h ; Test ECX
- jne @F
- cmp edx,44444444h ; Test EDX
- jne @F
- cmp ebp,55555555h ; Test EBP
- jne @F
- cmp edi,66666666h ; Test EDI
- jne @F
- cmp esi,77777777h ; Test ESI
- jne @F
- cmp esp,88888888h ; Test ESP
- jne short @F
- mov ax,cs ; Test CS
- cmp ax,1111h
- jne short @F
- mov ax,ds ; Test DS
- cmp ax,2222h
- jne short @F
- mov ax,es ; Test ES
- cmp ax,3333h
- jne short @F
- mov ax,fs ; Test FS
- cmp ax,4444h
- jne short @F
- mov ax,gs ; Test GS
- cmp ax,5555h
- jne short @F
- mov ax,ss ; Test SS
- cmp ax,6666h
- jne short @F
- cmp dword ptr ds:[0],02020202h ; Test DS Desc Cache
- jne short @F
- cmp dword ptr es:[0],03030303h ; Test ES Desc Cache
- jne short @F
- cmp dword ptr fs:[0],04040404h ; Test FS Desc Cache
- jne short @F
- cmp dword ptr gs:[0],05050505h ; Test GS Desc Cache
- jne short @F
- cmp dword ptr ss:[0],06060606h ; Test SS Desc Cache
- jne short @F
- mov ax,_Data ; Reset segment regs.
- mov ds,ax
- mov es,ax
- lss esp,fword ptr cs:stack_ptr ; Reset SS:ESP
- FARJMP <Loadall_test>,<seg _Text> ; Continue
-
- ;---------------------------------------------------------------
- ; Loadall failed the REGISTERs test.
- ;---------------------------------------------------------------
- @@: mov ax,_Data
- mov ds,ax
- mov es,ax
- lss esp,fword ptr cs:stack_ptr
- FARJMP <@F>,<seg _Text>
- @@: Print_String failed
- Print_String RFail
- jmp loadall_ret
-
- ;---------------------------------------------------------------
- ; LOADALL passed
- ;---------------------------------------------------------------
- Loadall_test:
- Print_String passed
-
- ;---------------------------------------------------------------
- ;
- ; TEST2: Access extended memory while in real mode (@ 2M).
- ;
- ; (1) Fill in LOADALL structure with "reasonable" values
- ; (2) Save contents of extended memory
- ; (3) Write data pattern in extended memory
- ; (4) Set LOADALL registers used by this test
- ; (5) LOADALL
- ; (6) Verify results
- ; (7) Restore original data in extended memory
- ;
- ;---------------------------------------------------------------
- ; In this test, I'll access extended memory while in real mode.
- ; I'll assume the computer has at least 2M of memory. By
- ; assuming 2M, I don't need to enable A20 on the CPU bus, since
- ; memory @ 2M doesn't assert A20.
- ;---------------------------------------------------------------
- ; Fill LOADALL structure with more reasonable values.
- ;---------------------------------------------------------------
- mov Loadall_tbl._EAX,0
- mov Loadall_tbl._EBX,0
- mov Loadall_tbl._ECX,0
- mov Loadall_tbl._EDX,0
- mov Loadall_tbl._EBP,0
- mov Loadall_tbl._ESP,esp
- mov Loadall_tbl._CS,cs
- mov Loadall_tbl._DS,ds
- mov Loadall_tbl._ES,es
- mov Loadall_tbl._FS,8000h
- mov Loadall_tbl._GS,8000h
- mov Loadall_tbl._SS,ss
-
- ;---------------------------------------------------------------
- ; Load segment descriptor cache registers:
- ; DS=ES = _DATA segment
- ; FS=GS = 80000h (8000:0)
- ; SS = STACK segment
- ;---------------------------------------------------------------
- mov ax,ds
- movzx eax,ax
- shl eax,4
- mov bx,ss
- movzx ebx,bx
- shl ebx,4
- mov Loadall_tbl.DS_Desc._addr,eax
- mov Loadall_tbl.ES_Desc._addr,eax
- mov Loadall_tbl.FS_Desc._addr,80000h;
- mov Loadall_tbl.GS_Desc._addr,80000h
- mov Loadall_tbl.SS_Desc._addr,ebx
-
- ;---------------------------------------------------------------
- ; Slip into protected mode to save the contents of memory @ 2M,
- ; and write a test pattern into that memory.
- ;---------------------------------------------------------------
- Print_String Test_2
- lgdt fword ptr Gdt_386 ; Load the GDT
- mov ebx,cr0 ; enter protected mode
- or bl,1
- mov cr0,ebx
- FARJMP <@F>,<CSEG3-Gdt_386>
-
- @@: mov dx,DSEG3-Gdt_386 ; Get segment selector
- mov ds,dx ; for DS @ 2M
- mov cx,400h / 4
- mov si,0
- mov di,offset Mem_buffer
- rep movsd ; Save memory
- mov eax,5aa5aa5ah ; Test pattern
- mov cx,400h / 4
- mov di,0
- mov es,dx ; ES = 2M
- rep stosd ; Store test pattern
- and bl,not 1 ; exit protected mdoe
- mov cr0,ebx
- FARJMP <@F>,<_TEXT>
-
- ;---------------------------------------------------------------
- ; Set LOADALL-image registers used by this test
- ;---------------------------------------------------------------
- @@: mov ax,_data
- mov ds,ax
- mov es,ax
- mov Loadall_tbl._EAX,5aa5aa5ah ; Test pattern
- mov Loadall_tbl._ECX,400h / 4 ; # of DWORDS
- mov Loadall_tbl._ESI,offset Mem_buffer
- mov Loadall_tbl._EDI,0h ; ES:0
- mov Loadall_tbl._EIP,offset @F ; EIP
- mov Loadall_tbl.ES_Desc._Addr,200000h ; 2M
- mov edi,offset loadall_tbl
- LOADALL
-
- ;---------------------------------------------------------------
- ; Check memory for a match of the pattern
- ;---------------------------------------------------------------
- @@: repz scasd ; data match?
- mov bx,_Data ; ES still points to 2M,
- mov ds,bx ; so I can reset DS and
- mov cx,400h / 4 ; restore the original
- mov di,0 ; contents @ 2M without
- rep movsd ; changing ES.
- mov es,bx ; Set ES to real mode
- lss esp,fword ptr cs:stack_ptr ; Restore SS:ESP
- FARJMP <@F>,<_TEXT> ; Must jump to R/W CS
- @@: jz short @Test2_Pass
-
- PRINT_STRING failed
- jmp short @Test3
-
- @Test2_Pass:
- PRINT_STRING passed
-
- ;---------------------------------------------------------------
- ;
- ; TEST3: Test that the Present bit gets loaded w/out exception,
- ; but when a segment is accessed INT13 get generated.
- ;
- ; (1) Load GDT & IDT pointers into LOADALL table
- ; (2) Set PM bit, CS selector, EIP offset, clear P bit
- ; (3) LOADALL
- ; (4) Verify Results
- ;
- ;-----------------------------------------------------------------------------
- @Test3: Print_String Test_3
-
- ;---------------------------------------------------------------
- ; Initialize the GDT & IDT descriptor cache
- ;---------------------------------------------------------------
- mov eax,Loadall_tbl.DS_Desc._Addr
- mov ebx,eax
- mov Loadall_tbl.ES_Desc._Addr,eax
- add eax,offset Gdt_386
- add ebx,offset Idt_386
- mov Loadall_tbl.GDT_Desc._Addr,eax
- mov Loadall_tbl.GDT_Desc._Limit,Gdt3_len-1
- mov Loadall_tbl.Idt_Desc._Addr,ebx
- mov Loadall_tbl.Idt_Desc._Limit,Idt3_len-1
-
- or Loadall_tbl._CR0,1 ; set PM bit
- mov Loadall_tbl._ESI,0
- mov Loadall_tbl._CS,CSEG3-Gdt_386 ; CS selector
- mov Loadall_tbl._EIP,offset @Test_Present
- and Loadall_tbl.GS_Desc._Type,7fh ; clear Present
- mov edi,offset loadall_tbl ; bit in GS
- LOADALL
-
- @Test_Present:
- mov si,gs:[si][2] ; choose this because
- ; it's a 4-byte instr.
- Lidt fword ptr RM_IDT3_Ptr ; Restore real-mode IDT
- mov eax,cr0 ; Exit protected mode.
- and al,not 1
- mov cr0,eax
- FARJMP <@F>,<_TEXT> ; Return to R/W, real-
- ; mode code segment
-
- @@: test si,1 ; pass test?
- jnz short @F ; yep
- Print_String failed
- jmp short @Test4
-
- @@: Print_String passed
-
- ;---------------------------------------------------------------
- ;
- ; TEST4: Test 32-bit Protected Mode operation
- ;
- ; (1) Set LOADALL operand size, PM bits, and EIP offset
- ; (2) LOADALL
- ; (3) Verify Results
- ;
- ;---------------------------------------------------------------
- @Test4: Print_String Test_4
-
- ;---------------------------------------------------------------
- ; Perform 32-bit protected mode test
- ;---------------------------------------------------------------
- or Loadall_tbl.CS_Desc._CS32,40h ; CS32 bit
- mov Loadall_tbl._EDI,offset Loadall_tbl
- mov Loadall_tbl._EIP,offset PM32
- LOADALL
-
- ;---------------------------------------------------------------
- ; This test uses a simple technique to determine if we are in
- ; 32-bit mode or 16-bit mode:
- ;
- ; In 16-bit mode, this code will be executed as:
- ; mov si,1234h
- ; nop
- ; nop
- ;
- ; In 32-bit mode, this code will be executed as:
- ; mov esi,90901234h ; The two NOP's are absorbed
- ; ; into the 32-bit operand.
- ;
- ;---------------------------------------------------------------
- ;---------------------------------------------------------------
- ; In 16-bit mode, this code will be executed as:
- ; mov di,1234h
- ; nop
- ; nop
- ;
- ; In 32-bit mode, this code will be executed as:
- ; mov edi,90901234h
- ;---------------------------------------------------------------
- PM32: mov si,1234h
- nop
- nop
-
- ;---------------------------------------------------------------
- ; Now, we need to exit 32-bit mode gracefully. In order to do
- ; that, we need code that will generate predictable results in
- ; both 32-bit, and 16-bit mode. If we are in 32-bit mode, then
- ; the following compiled code will behave as documented under
- ; the '32-bit mode' column. If we failed to enter 32-bit mode,
- ; then the following compiled code will behave as documented
- ; under the '16-bit mode' column. In order to exit gracefully,
- ; we need to know which mode we are in! Hence the following
- ; code to detect it!:
- ;
- ; 16-bit mode 32-bit mode
- ; push ax push eax
- ; mov ax,si mov eax,esi
- ; shr ax,10h shr eax,10h ; AX=9090 if in 32-bit
- ; ; AX=0 if in 16-bit
- ;
- ; cmp al,90h cmp al,90h ; PASS=32-bit, FAIL=16-bit
- ; pushf pushf ; save results for later
- ; shl ax,10h shl eax,10h ; EAX=90900000 if in 32-bit
- ; mov si,ax mov esi,eax ; ESI=90900000 if in 32-bit
- ; ; ESI=66660000 if in 16-bit
- ; popf popf ; restore ZF
- ; pop ax pop eax
- ;
- ; So, the result of this code is to exit 32-bit mode if we got
- ; there, and to keep going in 16-bit mode if we didn't.
- ;---------------------------------------------------------------
- push ax ; See the above
- mov ax,si ; explanation on how
- shr ax,10h ; this code works
- cmp al,90h
- pushf
- shl ax,10h
- mov si,ax
- popf
- pop ax
- jne short @No_PM32bitCS
- or si,1 ; set SI if 32-bit mode
-
- ;---------------------------------------------------------------
- ; 32-bit JUMP instruction, to transfer control back to a 16-bit
- ; segment
- ;---------------------------------------------------------------
- LONGJMP <@F>,<CSEG3-GDT_386> ; Construct 32-bit far
- ; JMP
-
- @No_PM32bitCS: ; FAR JUMP if stuck in
- FARJMP <@F>,<CSEG3-GDT_386> ; 16-bit mode.
-
- @@: Lidt fword ptr RM_IDT3_Ptr ; Restore real-mode IDT
- mov eax,cr0 ; Exit protected mode.
- and al,not 1
- mov cr0,eax
- FARJMP <@F>,<_TEXT> ; Jump to real-mode
- ; code segment
- @@: mov ax,_Data ; Restore real-mode
- mov ds,ax ; segment registers
- mov es,ax
- test si,1 ; 32-bit mode passed?
- jnz short @F ; yep
- Print_String failed
- jmp short @Test5
-
- @@: Print_String passed
-
- ;---------------------------------------------------------------
- ;
- ; TEST5: Test 32-bit real-mode operation
- ;
- ; (1) Clear operand size, PM bits, and set EIP offset
- ; (2) LOADALL
- ; (3) Verify Results
- ; (4) Get the h&*@! out of 32-bit real-mode
- ;
- ;---------------------------------------------------------------
- ; Test 32-bit real-mode operation. Make sure we can put the
- ; processor in an illegal state: 32-bit real-mode.
- ;---------------------------------------------------------------
- @Test5: Print_String Test_5
- and Loadall_tbl._CR0,not 1 ; disable PM bit
- and Loadall_tbl.CS_Desc._Type,not 8 ; make CS R/W
- ; Data segment
- mov Loadall_tbl._EIP,offset RM32 ; Load EIP
- LOADALL
-
- ;---------------------------------------------------------------
- ; This test uses the exact same technique documented in TEST4.
- ; See TEST4 for an explanation of these next two code sections.
- ;---------------------------------------------------------------
- RM32: mov si,1234h
- nop
- nop
-
- ;---------------------------------------------------------------
- ; See TEST4 for an explanation of this code section.
- ;---------------------------------------------------------------
- push ax ; See the above
- mov ax,si ; explanation on how
- shr ax,10h ; this code works
- cmp al,90h
- pushf
- shl ax,10h
- mov si,ax
- popf
- pop ax
-
- ;---------------------------------------------------------------
- ; Now getting out of 32-bit real mode is a bit more complicated
- ; than you may think. According to Intel, the internal
- ; descriptor cache registers get re-loaded with default values
- ; each time the segment is loaded. But the operand size bit in
- ; the CS descriptor cache doesn't get cleared in a long jump.
- ; So, to program around this, I need to either execute LOADALL
- ; again, or go to protected mode, jump to a 16-bit code segment,
- ; then go back to real mode. I think I will do the latter.
- ;---------------------------------------------------------------
- jne short @RM32_Fail ; Do something else
- mov eax,cr0 ; Enter protected mode
- or al,1
- mov cr0,eax
- LONGJMP <@F>,<CSEG3-GDT_386> ; To 16-bit CS
-
- @@: Lidt fword ptr RM_IDT3_Ptr ; Reload real-mode IDT
- and al,not 1 ; Exit protected mode
- mov cr0,eax
- FARJMP <@RM32_Pass>,<seg _text>; Back to real-mode CS
-
- @RM32_Fail:
- Print_String failed
- jmp short @Test6
-
- @RM32_Pass:
- mov ax,_Data ; Reload real-mode
- mov ds,ax ; segment registers
- mov es,ax
- Print_String passed
-
- ;---------------------------------------------------------------
- ;
- ; TEST6: Test Granularity bit. Test that the granularity bit
- ; in the descriptor cache has no effect on the limit
- ; field of the descriptor cache. This is a three-part
- ; test. First, by setting G=1 in a segment descriptor
- ; cache whose limit=64k should cause an exception.
- ; Second, ES_LIMIT=16M-4. This LIMIT can't ever be
- ; generated under program control. So we simply need
- ; to access memory @ 16M-8 to verify this test. If
- ; an exception gets generated, then the test failed.
- ; Third, try to access memory @ 16M-4. If an exception
- ; ISN'T generated, then the test failed.
- ;
- ; (1) Set Present, Granularity bits, and EIP offset
- ; (2) LOADALL
- ; (3) Verify results
- ;
- ;---------------------------------------------------------------
- ; Test Granularity bit: Test that G=1 has no effect in the
- ; descriptor cache register. In the GS descriptor cache, I set
- ; the limit=64k. If G=1 has any effect on this field, then the
- ; following memory access will pass. We want it to fail, and
- ; generate an exception-13.
- ;---------------------------------------------------------------
- @Test6: Print_String Test_6
- or Loadall_tbl._CR0,1 ; set PM bit
- or Loadall_tbl.GS_Desc._Type,80h ; set P=1
- or Loadall_tbl.GS_Desc._CS32,80h ; set G=1
- and Loadall_tbl.CS_Desc._CS32,0bfh ; clear CS32 bit
- mov Loadall_tbl._EIP,offset @Test_Gran
- LOADALL
-
- @Test_Gran:
- mov esi,10000h ; should generate exc.
- mov si,gs:[esi]
- shl si,1 ; save results
- mov esi,0fffff8h ; 16M-8
- mov si,es:[esi] ; shouldn't generate exc
- shl si,1
- mov esi,0fffffch ; 16M-4
- mov si,es:[esi] ; should generate exc.
- add esi,4
- Lidt fword ptr RM_IDT3_Ptr ; Restore real-mode IDT
- mov eax,cr0
- and al,not 1
- mov cr0,eax
- FARJMP <@F>,<_TEXT>
-
- @@: and si,7
- cmp si,5 ; pass test?
- jnz short @F ; yep
- Print_String failed
- jmp short @Test7
-
- @@: Print_String passed
-
- ;---------------------------------------------------------------
- ; The following two expamples show how to use the debug
- ; registers to generate execution and data break points. They
- ; are included in this program because they use LOADALL to set
- ; DR7. Forgive the fact that they are poorly documented.
- ;---------------------------------------------------------------
- ;
- ; TEST7: Test execution breakpoints through debug registers.
- ;
- ; (1) Clear granularity bit, set ES_LIMIT=64k, set EIP offset
- ; (2) Set breakpoint qualifiers
- ; (3) LOADALL
- ; (4) Generate execution breakpoints
- ; (5) Verify results
- ;
- ;---------------------------------------------------------------
- @Test7: Print_String Test_7
- and Loadall_tbl.GS_Desc._CS32,7fh ; set G=0
- mov Loadall_tbl.ES_Desc._Limit,0ffffh; limit=64k
- mov Loadall_tbl._EIP,offset Test_DR0
-
- ;---------------------------------------------------------------
- ; Set a series of execution break points in the debug registers.
- ;---------------------------------------------------------------
- mov bx,cs
- movzx ebx,bx
- shl ebx,4
- lea eax,[ebx][dword ptr Test_Dr0]
- mov dr0,eax
- lea eax,[ebx][dword ptr Test_DR1]
- mov dr1,eax
- lea eax,[ebx][dword ptr Test_DR2]
- mov dr2,eax
- lea eax,[ebx][dword ptr Test_DR3]
- mov dr3,eax
- mov Loadall_tbl._DR7,0aah ; enable all code
- ; breakpoints
- LOADALL
-
- Test_DR0:
- nop
- Test_DR1:
- nop
- Test_DR2:
- nop
- Test_DR3:
- nop
-
- Lidt fword ptr RM_IDT3_Ptr ; Restore real-mode IDT
- mov eax,cr0 ; exit protected mode
- and al,not 1
- mov cr0,eax
- FARJMP <@F>,<seg _text>
-
- @@: and si,0fh
- cmp si,0fh ; pass all breakpoints?
- je short @F ; yep
- Print_String failed
- jmp @Test8
-
- @@: Print_String passed
-
- ;---------------------------------------------------------------
- ;
- ; TEST8: Test byte-size data write breakpoints
- ;
- ; (1) Set EIP offset
- ; (2) Set breakpoint qualifiers
- ; (3) LOADALL
- ; (4) Generate data breakpoints
- ; (5) Verify results
- ;
- ;---------------------------------------------------------------
- @Test8: Print_String Test_8
- mov Loadall_tbl._EAX,55h
- mov Loadall_tbl._ECX,40h
- mov Loadall_tbl._EDI,offset Buffer
- mov Loadall_tbl._EIP,offset @Test_DRBW
-
- mov bx,ds
- movzx ebx,bx
- shl ebx,4
- lea eax,[ebx][Dword ptr Buffer][3]
- mov dr0,eax
- add eax,10h
- mov dr1,eax
- add eax,10h
- mov dr2,eax
- add eax,10h
- mov dr3,eax
- mov Loadall_Tbl._DR7,111102aah
- LOADALL
-
- @Test_DRBW:
- rep stosb
- Lidt fword ptr RM_IDT3_Ptr
- mov ebx,cr0
- and bl,not 1
- mov cr0,ebx
- FARJMP <@F>,<seg _text>
-
- @@: and si,0fh
- cmp si,0fh ; pass all breakpoints?
- je short @T7P ; yep
- Print_String failed
- jmp @Test9
-
- @T7P: cmp dx,4 ; INT01 4 times?
- jne @B
- Print_String passed
-
- @Test9:
- jmp Loadall_ret
-
-
- LOADALL_386 endp
-
-
- ;---------------------------------------------------------------
- ; Minimal exception 13 handler that points past a 4-byte opcode,
- ; and sets the lowest bit in DI before returning.
- ;---------------------------------------------------------------
- INT13 label word
- push bp
- mov bp,sp
- add word ptr [bp][4],4
- or si,1
- pop bp
- add sp,2
- iret
-
-
- ;-----------------------------------------------------------------------------
- INT01: ; Int1 trap routine
- ;-----------------------------------------------------------------------------
- ; Interprets breakpoint type, and sets a flag
- ;-----------------------------------------------------------------------------
- inc dx
- push bp
- mov bp,sp
- mov buffer2[bx],cx
- add bx,2
- push eax
- push ebx
- push ecx
- mov eax,dr6
- mov ecx,eax
- mov ebx,dr7
- shr ebx,10h ; get length encodings
- test ah,20h ; debug register access attempt?
- jnz @DR_Attempt ; yep
- shr al,1 ; DR0?
- jc @DR0
- shr al,1 ; DR1?
- jc @DR1
- shr al,1 ; DR2?
- jc @DR2
- @DR3: or si,8
- and cl,not 8
- test bh,30h ; code, or data?
- jz @Fault
- jmp short @Trap
- @DR2: or si,4
- and cl,not 4
- test bh,03h ; code, or data?
- jz @Fault
- jmp short @Trap
- @DR1: or si,2
- and cl,not 2
- test bl,30h ; code, or data?
- jz @Fault
- jmp short @Trap
- @DR0: or si,1
- and cl,not 1
- test bl,03h ; code, or data?
- jz @Fault
- jmp short @Trap
- @Fault: add word ptr [bp][2],1
- mov dr6,ecx
- @Trap: pop ecx
- pop ebx
- pop eax
- pop bp
- iret
-
- @Dr_Attempt:
- push bp
- add word ptr [bp][2],3
- pop bp
- iret
-
-
-
-
- ;-----------------------------------------------------------------------------
- Save_state proc near ; Save the machine state before LOADALL
- ;-----------------------------------------------------------------------------
- push eax
- push ds
- mov si,0
- mov di,offset Machine_State.GS_Desc
- mov ax,5000h ; GS descriptor
- mov ds,ax
- mov ebx,05050505h
- movsd
- mov dword ptr [si-4],ebx
-
- sub ax,1000h ; FS descriptor
- sub ebx,01010101h
- mov si,0
- add di,8
- mov ds,ax
- movsd
- mov dword ptr [si-4],ebx
- sub ax,2000h ; DS descriptor
- sub ebx,02020202h
- mov si,0
- add di,8
- mov ds,ax
- movsd
- mov dword ptr [si-4],ebx
- add ax,4000h ; SS descriptor
- add ebx,04040404h
- mov si,0
- add di,8
- mov ds,ax
- movsd
- mov dword ptr [si-4],ebx
- sub ax,3000h ; ES descriptor
- sub ebx,03030303h
- mov si,0
- add di,14h
- mov ds,ax
- movsd
- mov dword ptr [si-4],ebx
- pop ds
-
- mov eax,cr0
- mov Machine_State._CR0,eax
- pushfd
- pop eax
- mov Machine_State._Eflags,eax
- pop eax
- mov Machine_State._EDI,edi
- mov Machine_State._ESI,esi
- mov Machine_State._EBP,ebp
- mov Machine_State._EBX,ebx
- mov Machine_State._EDX,edx
- mov Machine_State._ECX,ecx
- mov Machine_State._EAX,eax
- mov ax,gs
- movzx eax,ax
- mov Machine_State._GS,eax
- mov ax,fs
- mov Machine_State._FS,eax
- mov ax,ds
- mov Machine_State._DS,eax
- mov ax,es
- mov Machine_State._ES,eax
- ret
- Save_state endp
-
-
- ;-----------------------------------------------------------------------------
- Restore_state proc near ; Restore the machine state after LOADALL
- ;-----------------------------------------------------------------------------
- mov ax,_data
- mov ds,ax
- mov ax,5000h ; GS
- mov es,ax
- mov si,offset Machine_State.GS_Desc
- mov di,0
- movsd
- sub ax,1000h ; FS
- add si,8
- mov di,0
- mov es,ax
- movsd
- sub ax,2000h ; DS
- add si,8
- mov di,0
- mov es,ax
- movsd
- add ax,4000h ; SS
- add si,8
- mov di,0
- mov es,ax
- movsd
- sub ax,3000h ; ES
- add si,14h
- mov di,0
- mov es,ax
- movsd
- mov eax,Machine_State._ES
- mov es,ax
- mov eax,Machine_State._DS
- mov ds,ax
- mov eax,Machine_State._FS
- mov fs,ax
- mov eax,Machine_State._GS
- mov gs,ax
- mov eax,Machine_State._Eflags
- push eax
- popfd
- mov eax,Machine_State._CR0
- mov cr0,eax
- mov eax,Machine_State._EAX
- mov ecx,Machine_State._ECX
- mov edx,Machine_State._EDX
- mov ebx,Machine_State._EBX
- mov ebp,Machine_State._EBP
- mov esi,Machine_State._ESI
- mov edi,Machine_State._EDI
- ret
- Restore_State endp
-
-
- ;---------------------------------------------------------------
- ; Include the CPU_TYPE procedure & LOADALL test
- ;---------------------------------------------------------------
- Include CPU_TYPE.ASM
-
- _text ends
-
-
- stack segment para stack 'stack'
- db 400h dup (0)
- stack ends
-
- end LOADALL_386
-
-